package pacs.sgc.dao;

import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import pacs.sgc.classesbasicas.Endereco;
import pacs.sgc.classesbasicas.Funcionario;
import pacs.sgc.exceptions.AcessoAoBancoException;
import pacs.sgc.exceptions.ConexaoComBancoException;

public class FuncionarioDao implements IFuncionarioDao {
	private Conexao conexao;
	private PreparedStatement statement = null;
	private ResultSet rs = null;
	
	private EnderecoDao enderecoDao = FabricaDao.criarEnderecoDao();
	
	
	private final String SQL_INSERT = "INSERT INTO funcionario(matricula, nome, cpf, rg, funcao, dataNascimento, codEndereco, telefone, celular, email) " +
		"VALUES(?,?,?,?,?,?,?,?,?,?)"; //10 parametros	
	private final String SQL_DELETE = "DELETE FROM funcionario WHERE cpf = ?";
	private final String SQL_UPDATE = "UPDATE funcionario SET nome = ?, cpf = ?, rg = ?, funcao = ?, dataNascimento = ?, codEndereco = ?, " +
		"telefone = ?, celular = ?, email = ? WHERE matricula = ?";
	private final String SQL_SELECT = "SELECT matricula, nome, cpf, rg, funcao, dataNascimento, codEndereco, telefone, celular, email FROM funcionario WHERE cpf = ? OR rg = ?";
	private final String SQL_SELECT_CODIGO = "SELECT matricula, nome, cpf, rg, funcao, dataNascimento, codEndereco, telefone, celular, email FROM funcionario WHERE matricula = ?";
	private final String SQL_SELECT_TODOS = "SELECT matricula, nome, cpf, rg, funcao, dataNascimento, codEndereco, telefone, celular, email FROM funcionario";
	private final String SQL_SELECT_ULTIMO = "SELECT matricula FROM funcionario WHERE matricula = (SELECT MAX(matricula) FROM funcionario)";

		
	
	/**
	 * Construtor Default
	 *
	 */
	public FuncionarioDao(){
		this.conexao = FabricaConexao.criarConexao();
	}
	
	/**
	 * Construtor
	 * 
	 * @param conexao
	 */
	public FuncionarioDao(Conexao conexao){
		this.conexao = conexao;
	}

	
	
	/**
	 * Metodo que atualiza um funcionario existente
	 * 
	 * @param atualizado
	 * @return void
	 * @throws ConexaoComBancoException
	 * @throws AcessoAoBancoException
	 */
	public void atualizar(Funcionario atualizado) throws ConexaoComBancoException, AcessoAoBancoException {
		PreparedStatement update = null;
		try{
			this.conexao.abrirConexao();
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_SELECT_CODIGO);
			this.statement.setInt(1,atualizado.getMatricula());
			this.rs = statement.executeQuery();
			
			if(rs.next()){
				update = this.conexao.getCon().prepareStatement(this.SQL_UPDATE);
				
				update.setString(1, atualizado.getNome());
				update.setString(2, atualizado.getCpf());
				update.setString(3, atualizado.getRg());
				update.setString(4, atualizado.getFuncao());
				update.setDate(5, atualizado.getDataNascimento());
				update.setInt(6, atualizado.getEndereco().getCodigo());
				update.setString(7, atualizado.getTelefone());
				update.setString(8, atualizado.getCelular());
				update.setString(9, atualizado.getEmail());
				update.setInt(10, atualizado.getMatricula());
				
				update.execute();
				update.close();				
			}
		}catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{			
			try {
				if(this.conexao != null)
					this.conexao.fecharConexao();
				
				if(this.statement != null)
					this.statement.close();
				
				if(this.rs != null)
					this.rs.close();
				
				if(update != null)
					update.close();
			} catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}

	}

	/**
	 * Metodo que pega do banco a ultima matricula inserida na tabela funcionario e 
	 * gera a proxima matricula a ser inserida
	 * 
	 * @return int;
	 * @throws AcessoAoBancoException
	 * @throws ConexaoComBancoException
	 */
	public int gerarCodigo() throws ConexaoComBancoException, AcessoAoBancoException {
		int proximaMatricula = 1;
		try{
			this.conexao.abrirConexao();
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_SELECT_ULTIMO);
			
			this.rs = statement.executeQuery();
			
			if(this.rs.next())
				proximaMatricula = rs.getInt("matricula") + 1;
			
		} catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{			
			try {
				if(this.conexao != null)
					this.conexao.fecharConexao();
				
				if(this.statement != null)
					this.statement.close();
				
				if(this.rs != null)
					this.rs.close();
			} catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
		return proximaMatricula;
	}

	
	/**
	 * Metodo que insere um novo registro na tabela funcionario.
	 * 
	 * @param novoFuncionario
	 * @return void
	 * @throws AcessoAoBancoException
	 * @throws ConexaoComBancoException
	 */
	public void inserir(Funcionario novoFuncionario) throws ConexaoComBancoException, AcessoAoBancoException {
		try{
			this.conexao.abrirConexao();
			
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_INSERT);
			this.statement.setInt(1, novoFuncionario.getMatricula());
			this.statement.setString(2, novoFuncionario.getNome());
			this.statement.setString(3, novoFuncionario.getCpf());
			this.statement.setString(4, novoFuncionario.getRg());
			this.statement.setString(5, novoFuncionario.getFuncao());
			this.statement.setDate(6, novoFuncionario.getDataNascimento());
			this.statement.setInt(7, novoFuncionario.getEndereco().getCodigo());
			this.statement.setString(8, novoFuncionario.getTelefone());
			this.statement.setString(9, novoFuncionario.getCelular());
			this.statement.setString(10, novoFuncionario.getEmail());
			
			this.statement.execute();
		} catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{
			try{
				if(this.conexao != null)
					this.conexao.fecharConexao();
				if(this.statement != null)
					this.statement.close();	
			}catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
	}

	
	/**
	 * Metodo que lista todos os funcionarios cadastrado
	 * 
	 * @return List<Funcionario>
	 * @throws AcessoAoBancoException 
	 * @throws ConexaoComBancoException 
	 */
	public List<Funcionario> listar() throws ConexaoComBancoException, AcessoAoBancoException {
		List<Funcionario> listaDeFuncionarios = new ArrayList<Funcionario>();
		try{
			this.conexao.abrirConexao();
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_SELECT_TODOS);			
			this.rs = this.statement.executeQuery();
			
			while(rs.next()){
				int matricula = this.rs.getInt(1);
				String nome = this.rs.getString(2);
				String cpf = this.rs.getString(3);
				String rg = this.rs.getString(4);
				String funcao = this.rs.getString(5);
				Date dataNascimento = this.rs.getDate(6);
				Endereco endereco = enderecoDao.localizar(this.rs.getInt(7));
				String telefone = this.rs.getString(8);
				String celular = this.rs.getString(9);
				String email = this.rs.getString(10);
				
				listaDeFuncionarios.add(new Funcionario(matricula,nome,cpf,rg,funcao,dataNascimento,endereco,telefone,celular,email));
			}
			
		}catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{			
			try {
				if(this.conexao != null)
					this.conexao.fecharConexao();
				
				if(this.statement != null)
					this.statement.close();
				
				if(this.rs != null)
					this.rs.close();
			} catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
		return listaDeFuncionarios;
	}

	/**
	 * Metodo que localiza um funcionario apartir do seu cpf ou do seu rg.
	 * 
	 * @param cpf
	 * @param rg
	 * @return Funcionario
	 * @throws AcessoAoBancoException 
	 * @throws ConexaoComBancoException 
	 */
	public Funcionario localizar(String cpf, String rg) throws ConexaoComBancoException, AcessoAoBancoException {
		Funcionario localizado = null;
		try{
			this.conexao.abrirConexao();
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_SELECT);	
			this.statement.setString(1, cpf);
			this.statement.setString(2, rg);
			this.rs = this.statement.executeQuery();
			
			if(rs.next()){
				int matricula = this.rs.getInt(1);
				String nome = this.rs.getString(2);
				String cpf2 = this.rs.getString(3);
				String rg2 = this.rs.getString(4);
				String funcao = this.rs.getString(5);
				Date dataNascimento = this.rs.getDate(6);
				Endereco endereco = enderecoDao.localizar(this.rs.getInt(7));
				String telefone = this.rs.getString(8);
				String celular = this.rs.getString(9);
				String email = this.rs.getString(10);
				
				localizado = new Funcionario(matricula,nome,cpf2,rg2,funcao,dataNascimento,endereco,telefone,celular,email);
			}
			
		}catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{			
			try {
				if(this.conexao != null)
					this.conexao.fecharConexao();
				
				if(this.statement != null)
					this.statement.close();
				
				if(this.rs != null)
					this.rs.close();
			} catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
		return localizado;
	}
	
	/**
	 * Metodo que remove um registro da tabela funcionario que tenha o cpf igual ao cpf passado.
	 * 
	 * @param cpf
	 * @return void
	 * @throws AcessoAoBancoException
	 * @throws ConexaoComBancoException
	 */
	public void remover(String cpf) throws ConexaoComBancoException, AcessoAoBancoException {
		try{
			this.conexao.abrirConexao();
			
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_DELETE);
			this.statement.setString(1, cpf);
			this.statement.execute();
			
		}catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{
			try{
				if(this.conexao != null)
					this.conexao.fecharConexao();
				if(this.statement != null)
					this.statement.close();	
			}catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
	}

}
